package com.zimin.authorize.aspect;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.zimin.authorize.annotation.Authorize;
import com.zimin.authorize.constant.AuthorizeConstant;
import com.zimin.common.constant.ServletConstant;
import com.zimin.common.exception.GraceException;
import com.zimin.common.utils.AopUtils;
import com.zimin.common.utils.ServletUtil;
import com.zimin.common.utils.StringUtils;
import com.zimin.redis.constant.authorize.AuthorizeRedisConstant;
import com.zimin.redis.utils.RedisOperator;
import com.zimin.shared.annotation.OpLog;
import com.zimin.shared.enums.ResponseStatusEnum;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PatternMatchUtils;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;

/**
 * 授权 切面类
 *
 * @since 2020/12/20
 */
@Aspect
@Component
public class AuthorizeAspect {

    @Autowired
    private RedisOperator redisOperator;

    @Around("@annotation(authorize)")
    public Object around(ProceedingJoinPoint point, Authorize authorize) throws Throwable {
        var annotation =  AopUtils.getAnnotation(point, Authorize.class);
        if (annotation == null) {
            return point.proceed();
        }
        if (StringUtils.isNotEmpty(annotation.hasPerMi())) {
            if (hasPerMi(annotation.hasPerMi())) {
                return point.proceed();
            }
            GraceException.display(ResponseStatusEnum.FAILED);
        }
        return point.proceed();
    }

    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return
     */
    private boolean hasPerMi(String permission) {
        var o = redisOperator.get(String.format(AuthorizeRedisConstant.REDIS_LOGIN_PERMISSIONS, ServletUtil.getToken()));
        var menuPermissions = JSON.parseObject(JSON.toJSONString(o), List.class);
        if (!CollectionUtils.isEmpty(menuPermissions)) {
            return hasPermissions(menuPermissions, permission);
        }
        return Boolean.FALSE;
    }

    private boolean hasPermissions(Collection<String> authorities, String permission) {
        return authorities.stream().filter(StringUtils::hasText)
                .anyMatch(x -> AuthorizeConstant.ADMIN_MENU_PERMISSIONS.contains(StrUtil.trim(x))
                        || PatternMatchUtils.simpleMatch(StrUtil.trim(permission), StrUtil.trim(x)));
    }
}
